from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QWidget,QLabel,QVBoxLayout,QProgressBar,QMessageBox
from PyQt5.QtCore import QThread,QPropertyAnimation,pyqtSignal,QRect
from io import BytesIO
import lzma
import socket
import os


import hook_socket


class Demo_See(QWidget):
    def __init__(self,parent,title='title',IP="192.168.50.81",pos_xy=(1280,720),per=None):
        super(Demo_See,self).__init__()
        self.appid = title
        self.windows = per
        self.pos_x = pos_xy[0]
        self.pos_y = pos_xy[1]
        self.stop_threads = False
        self.setWindowTitle(self.appid+"查看中")
        layout = QVBoxLayout()
        self.lab1 = QLabel()
        self.pixmap = QPixmap()
        self.resize(self.pos_x+22,self.pos_y+22)
        self.setFixedSize(self.pos_x+22,self.pos_y+22)
        layout.addWidget(self.lab1)
        self.setLayout(layout)
        self.animation = QPropertyAnimation(self, b'windowOpacity')
        self.animation.setDuration(500)
        self.animation.stop()
        self.animation.setStartValue(0)
        self.animation.setEndValue(1)
        self.animation.start()
        if pos_xy[2] == 'tcp':
            self.thread = Sock_Tcp(self,IP)
        else:
            self.thread = Sock_Udp(self,IP)
        self.thread.pic_thread.connect(self.setbtme)
        self.thread.dic_thread.connect(self.close)
        self.thread.start()

    def setbtme(self,data):
        self.pixmap.loadFromData(data)
        self.lab1.setPixmap(self.pixmap)

    def closeEvent(self, event):
        if self.stop_threads == True:
            self.windows.Show(True)
            event.accept()
            self.close()
        else:
            event.ignore()
            self.stop_threads = True
            self.animation.stop()
            self.animation.finished.connect(self.close)
            self.animation.setStartValue(1)
            self.animation.setEndValue(0)
            self.animation.start()
            self.thread.terminate()


class Demo_Comm(QWidget):
    def __init__(self,parent,title='title',IP="192.168.50.81",pos_xy=(1280,720),sok=None,soc=None,per=None):
        super(Demo_Comm,self).__init__()
        self.web_sock_send = sok
        self.sock_send = soc
        self.appid = title
        self.windows = per
        self.pos_x = pos_xy[0]
        self.pos_y = pos_xy[1]
        self.stop_threads = False

        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.setWindowTitle(self.appid)
        
        layout = QVBoxLayout()
        self.lab1 = QLabel()
        self.pixmap = QPixmap()
        self.resize(self.pos_x+22,self.pos_y+22)
        self.setFixedSize(self.pos_x+22,self.pos_y+22)
        self.lab1.setMouseTracking(True)
        layout.addWidget(self.lab1)
        self.setLayout(layout)
        self.animation = QPropertyAnimation(self, b'windowOpacity')
        self.animation.setDuration(500)
        self.animation.stop()
        self.animation.setStartValue(0)
        self.animation.setEndValue(1)
        self.animation.start()
        if pos_xy[2] == 'tcp':
            self.thread = Sock_Tcp(self,IP)
        else:
            self.thread = Sock_Udp(self,IP)
        self.thread.pic_thread.connect(self.setbtme)
        self.thread.dic_thread.connect(self.close)
        self.thread.start()

    def dragEnterEvent(self,event):
        file = event.mimeData().text()
        ip = socket.gethostbyname(socket.gethostname())
        for pa in file.split("\n"):
            port = hook_socket.ret_prot()
            if port and pa:
               name = os.path.basename(pa[8:])
               size = os.path.getsize(pa[8:])
               progress("update",pa[8:],(ip,port),'qt').show()
               self.web_sock_send.put({'type':'send','data':{'type':'update','report':False,'msg':{'name':name, 'size':size,'ip':(ip,port)},'list':[self.appid]}})
               
            else:
               QMessageBox.question(self,"传输提示",pa + "传输失败，请稍后再试",QMessageBox.Yes)

    def mousePressEvent(self, event): 
        x,y = event.pos().x()-12, event.pos().y()-12
        if event.button() == 1:
            mak = 'left'
        elif event.button() == 2:
            mak = 'right'
        x,y = int((x/self.pos_x)*1920), int((y/self.pos_y)*1080)
        send_msg = hook_socket.return_send(typ='mouse_down',x=x,y=y,flag=mak)
        self.thread.on_send(send_msg)
    
    def mouseReleaseEvent(self, event): 
        x,y = event.pos().x()-12, event.pos().y()-12
        if event.button() == 1:
            mak = 'left'
        elif event.button() == 2:
            mak = 'right'
        x,y = int((x/self.pos_x)*1920), int((y/self.pos_y)*1080)
        send_msg = hook_socket.return_send(typ='mouse_up',x=x,y=y,flag=mak)
        self.thread.on_send(send_msg)
   
    def mouseDoubleClickEvent(self, event): 
        x,y = event.pos().x()-12, event.pos().y()-12
        if event.button() == 1:
            mak = 'left'
        elif event.button() == 2:
            mak = 'right'
        x,y = int((x/self.pos_x)*1920), int((y/self.pos_y)*1080)
        send_msg = hook_socket.return_send(typ='click',x=x,y=y,flag=mak)
        self.thread.on_send(send_msg)

    def mouseMoveEvent(self, event): 
        x,y = event.pos().x()-12, event.pos().y()-12
        x,y = int((x/self.pos_x)*1920), int((y/self.pos_y)*1080)
        send_msg = hook_socket.return_send(typ='move',x=x,y=y)
        self.thread.on_send(send_msg)

    def wheelEvent(self,event):
        send_msg = hook_socket.return_send(typ='wheel',flag=event.angleDelta().y())
        self.thread.on_send(send_msg)

    def leaveEvent(self, event):
        pass
 
    def setbtme(self,data):
        self.pixmap.loadFromData(data)
        self.lab1.setPixmap(self.pixmap)

    def closeEvent(self, event):
        if self.stop_threads == True:
            self.thread.on_send(hook_socket.return_send(typ='close'))
            self.sock_send.put({'type':'del','app':self.appid})
            if self.appid in self.windows.app:
                self.windows.app.pop(self.appid)
            self.windows.Show(True)
            event.accept()
            self.close()
        else:
            event.ignore()
            self.stop_threads = True
            self.animation.stop()
            self.animation.finished.connect(self.close)
            self.animation.setStartValue(1)
            self.animation.setEndValue(0)
            self.animation.start()
            self.thread.terminate()


class progress(QWidget):
    def __init__(self,sh,path,ipport,n):
        super(progress, self).__init__()
        self.stop_threads = False
        if n == 'qt':
            self.setWindowTitle(os.path.basename(path))
        else:
            self.setWindowTitle(n)
        self.setFixedSize(300, 40)
        self.progressBar = QProgressBar(self)
        self.progressBar.setGeometry(QRect(5, 5, 300, 30))
        if sh == "update":
            self.thread_1 = progress_send(self,ipport,path)
        else:
            self.thread_1 = progress_recv(self,ipport,path)
        self.thread_1.progressBarValue.connect(self.copy_file)
        self.thread_1.start()

    def closeEvent(self, event):
        if self.stop_threads == True:
            event.accept()
            self.close()
        else:
            ret = QMessageBox.question(self,"终止传输","确定终止传输吗?",QMessageBox.Yes|QMessageBox.No)
            if ret == 16384:
                event.accept()
                self.stop_threads = True
                self.close()
            else:
                event.ignore()

    def copy_file(self, i):
        if i == 100:
            self.stop_threads = True
            self.close()
        else:
            self.progressBar.setValue(i)


class progress_send(QThread):

    progressBarValue = pyqtSignal(int)

    def __init__(self,window,ip,path):
        super(progress_send, self).__init__()
        self.window = window
        self.ip = ip
        self.path = path
        self.size = os.path.getsize(self.path)

    def run(self):
        try:
            tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            tcp_server.bind(self.ip)
            tcp_server.listen(1)
            new_socket, client_addr = tcp_server.accept()
            s = open(self.path,'rb')
            n = 0
            while True:
                try:
                    m = s.read(4096)
                    if not m or self.window.stop_threads:
                        break
                    n += 4096
                    self.progressBarValue.emit(int((n/self.size)*100))
                    new_socket.send(m)
                except:
                    break
            s.close()
            new_socket.close()
            tcp_server.close()
        except Exception as e:
            print("progress_send",e)
        self.progressBarValue.emit(100)


			
class progress_recv(QThread):

    progressBarValue = pyqtSignal(int)

    def __init__(self,window,ip,Namesize):
        super(progress_recv, self).__init__()
        self.window = window
        self.ip = ip
        self.size = Namesize[0]
        self.name = Namesize[1]

    def run(self):
        path = os.path.join('C:\\Users',os.getlogin(),'Desktop',self.name)
        s = open(path,'wb')
        try:
            client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
            client.connect(self.ip)
            n = 0
            while True:
                try:
                    data = client.recv(4096)
                    if not data or self.window.stop_threads:
                        break
                    n += 4096
                    self.progressBarValue.emit(int((n/self.size)*100))
                    s.write(data)
                except:
                    break
            client.close()
        except Exception as e:
            print("progress_recv",e)
        s.close()
        self.progressBarValue.emit(100)



class Sock_Tcp(QThread):
    def __init__(self,window,IP):
        super(Sock_Tcp, self).__init__()
        self.window = window
        self.IP = IP

    pic_thread = pyqtSignal(bytes)
    dic_thread = pyqtSignal()

    def run(self):
        self.client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        self.client.connect((self.IP[0],self.IP[1]))
        while True:
            try:
                if self.window.stop_threads:
                    break
                recv_data = self.client.recv(1024*1024)
                by = BytesIO(lzma.decompress(recv_data))
                data = by.read()
                by.close()
                self.pic_thread.emit(data)
            except lzma.LZMAError:
                print("LZMAError")  
            except Exception as e:
                print("Sock_Tcp",e)
                break
        self.dic_thread.emit()
        self.client.close()

    def on_send(self,msg):
        try:
            self.client.send(msg.encode('utf-8'))
        except:
            pass


class Sock_Udp(QThread):
    def __init__(self,window,IP):
        super(Sock_Udp, self).__init__()
        self.window = window
        self.IP = IP

    pic_thread = pyqtSignal(bytes)
    dic_thread = pyqtSignal()

    def run(self):
        self.client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        #self.client.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF, 1024*1024)
        self.on_send(hook_socket.return_send(typ='start'))
        data = b''
        while True:
            try:
                if self.window.stop_threads:
                    break
                recv_data,addr = self.client.recvfrom(32500)
                if recv_data[0:4] == b'stop':
                    by = BytesIO(lzma.decompress(data))
                    self.pic_thread.emit(by.read())
                    by.close()
                    data = b''
                else:
                    data += recv_data
            except lzma.LZMAError:
                print("LZMAError")
                data = b''
            except Exception as e:
                print("Sock_Udp",e)
                break
        self.dic_thread.emit()
        self.client.close()

    def on_send(self,msg):
        try:
            self.client.sendto(msg.encode('utf-8'),(self.IP[0],self.IP[1]))
        except:
            pass